<template>
  <div>
    <div ref="three" class="three"></div>
  </div>
</template>

<script setup>
import * as THREE from "three";
// 导入压缩方法
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ref, onMounted } from "vue";

// 定义一个响应式引用对象，用于存储3D场景的各种配置
const options = ref({
  scene: null, // 场景对象，初始值为null
  camera: null, // 相机对象，初始值为null
  renderer: null, // 渲染器对象，初始值为null
  controls: null, // 控制器对象，用于控制相机的移动等，初始值为null
  clock: null, // 时钟对象，用于计算时间，初始值为null
});
let animationMixer = ref(null) // 动画混合器对象，用于管理动画，初始值为null
// 定义模型初始材质
const bodyMaterial = new THREE.MeshPhysicalMaterial({
  color: "#2e4e61",
  metalness: 1,
  roughness: 0.5,
  clearcoat: 1.0,
  clearcoatRoughness: 0.03,
});
const three = ref(null);
animationMixer.value = new THREE.AnimationMixer(options.value.scene) // 常见动画混合器
options.value.clock = new THREE.Clock()  // 时钟
const initThree = () => {
  // 1 创建场景
  options.value.scene = new THREE.Scene();
  // 2.1 创建相机  透视相机
  // fov:角度  aspect:宽高比  near:近端  far:远端
  options.value.camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    1,
    1000
  );
  // 2.2 设置相机位置
  options.value.camera.position.set(-20, -20, -44);
  // 2.3 将相机添加到场景中
  options.value.scene.add(options.value.camera);

  // 3 创建地面
  // 3.1 创建地面颜色
  const floorMat = new THREE.MeshPhysicalMaterial({
    color: 0xa9a9a9, // 材质的颜色
  });
  // 3.2 创建地面几何体
  const floorGeometry = new THREE.BoxGeometry(300, 300, 0.01, 1, 1, 1);
  // 3.3 创建地面
  const floorMesh = new THREE.Mesh(floorGeometry, floorMat);
  // 3.4 设置地面接收阴影
  floorMesh.receiveShadow = true;
  // 3.5 设置floorMesh的X轴旋转角度为-π/2弧度，使其与Y轴垂直
  floorMesh.rotation.x = -Math.PI / 2.0;
  // 3.6 将地面添加到场景中
  options.value.scene.add(floorMesh);

  // 给场景增加环境光
  // 设置环境光
  options.value.scene.add(new THREE.AmbientLight(0xffffff, 0.5));
  // 添加球光源
  const hesLight = new THREE.HemisphereLight(0xffffff, 0x444444);
  hesLight.intensity = 0.6;
  options.value.scene.add(hesLight);
  // 自然光
  // const dirLight = new THREE.DirectionalLight()
  // dirLight.position.set(0, 0, 15)
  // options.value.scene.add(dirLight)
  const dirLight2 = new THREE.DirectionalLight();
  dirLight2.position.set(0, 0, -15);
  options.value.scene.add(dirLight2);
  const dirLight3 = new THREE.DirectionalLight();
  dirLight3.position.set(15, 0, 0);
  options.value.scene.add(dirLight3);
  const dirLight4 = new THREE.DirectionalLight();
  dirLight4.position.set(-15, 0, 0);
  options.value.scene.add(dirLight4);
  const dirLight5 = new THREE.DirectionalLight();
  dirLight5.position.set(0, 15, 0);
  options.value.scene.add(dirLight5);
  const dirLight6 = new THREE.DirectionalLight();
  dirLight6.position.set(0, -15, 0);
  options.value.scene.add(dirLight6);
  const dirLight7 = new THREE.DirectionalLight();
  dirLight7.position.set(5, 15, 5);
  options.value.scene.add(dirLight7);
  const dirLight8 = new THREE.DirectionalLight();
  dirLight8.position.set(-5, -15, -5);
  options.value.scene.add(dirLight8);
  // 聚光灯
  const sportLight = new THREE.SpotLight(0xffffff, 0.8);
  sportLight.angle = Math.PI / 8; // 散射角度，跟水平线的夹角
  sportLight.penumbra = 0.1; // 聚光锥的半影衰减百分比
  sportLight.decay = 2; // 纵向：沿着光照距离的衰减量。
  sportLight.distance = 10;
  sportLight.shadow.radius = 10;
  // 阴影映射宽度，阴影映射高度
  sportLight.shadow.mapSize.set(512, 512);
  sportLight.position.set(0, 15, 0);
  // 光照射的方向
  sportLight.target.position.set(0, 0, 0);
  sportLight.castShadow = true;
  options.value.scene.add(sportLight);

  // 加载模型
  let dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath("./3D/textures/"); // 设置public下的解码路径，注意最后面的/
  dracoLoader.setDecoderConfig({ type: "js" }); //使用兼容性强的draco_decoder.js解码器
  dracoLoader.preload();

  const modelUrl = "/3D/"; // 定义所使用模型路径路径
  const loader = new GLTFLoader().setPath(modelUrl);
  loader.setDRACOLoader(dracoLoader);
  loader.load("scene.gltf", (gltf) => {
    console.log(gltf);
    gltf.scene.name = "3dmodel";
    gltf.scene.traverse(function (child) {
      // console.log(child)
      if (child.isMesh) {
        child.frustumCulled = false;
        // 模型阴影
        child.castShadow = true;
        // 模型自发
        child.material.emissive = child.material.color;
        child.material.emissiveMap = child.material.map;
      }
      // 获取不同部位
      if (
        child.isMesh &&
        child.name.indexOf("boot") !== -1 &&
        child.name.indexOf("boot004") === -1
      ) {
        child.material = bodyMaterial;
      }
    });
    gltf.scene.scale.set(13, 13, 13);
    gltf.scene.rotateY(Math.PI);
    gltf.scene.rotation.z = Math.PI;
    gltf.scene.position.set(0, 9, 0);
    options.value.scene.add(gltf.scene);
  });
  // 初始化渲染器
  options.value.renderer = new THREE.WebGLRenderer();
  options.value.renderer.shadowMap.enabled = true;
  options.value.renderer.antialias = true;
  console.log(options.value.renderer);
  
  // 设置渲染的尺寸大小
  options.value.renderer.setSize(window.innerWidth, window.innerHeight);
  options.value.renderer.setClearColor(0xffffff, 1.0);
  // 监听屏幕大小的改变，修改渲染器的宽高和相机的比例：
  window.addEventListener("resize", () => {
    options.value.renderer.setSize(window.innerWidth, window.innerHeight);
    options.value.camera.aspect = window.innerWidth / window.innerHeight;
    options.value.camera.updateProjectionMatrix();
  });

  // 将webgl渲染的canvas内容添加到body上
  three.value.appendChild(options.value.renderer.domElement);
  // 创建轨道控制器
  options.value.controls = new OrbitControls(
    options.value.camera,
    options.value.renderer.domElement
  );
  // 上下旋转范围
  options.value.controls.minPolarAngle = 0; // 默认值0
  options.value.controls.maxPolarAngle = Math.PI / 2.1; // 默认值Math.PI

  options.value.controls.enableDamping = true; // 开启阻尼
  options.value.controls.dampingFactor = 0.1;
  options.value.controls.enableZoom = false;
  options.value.controls.addEventListener("change", (event) => {
    console.log(event);
  });
  render();
};
const render = () => {
  options.value.controls && options.value.controls.update(); // 每一帧都需要更新
  animationMixer.value.update(options.value.clock.getDelta()); // 更新动画
  options.value.renderer.render(options.value.scene, options.value.camera);
  // 渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render);
};

const setCarColor = (color) => {
  console.log(color);
  // 通过点击不同的色块，给初始的模型材质赋值
  bodyMaterial.color.set(color);
};
onMounted(() => {
  initThree();
});
</script>

<style lang="scss" scoped></style>
